#include <vector>
#include "boost/asio/connect.hpp"

#include "mpHttpConnectionManageTests.h"
#include "mpHttpConnectionManage.h"
#include "mpAppUtils.h"
#include "mpLog.h"


using namespace MP::HTTP;

mpHttpConnectionManageTests::mpHttpConnectionManageTests()
{
    _schema = "http";
    _host = "localhost";
    _port = "5000";

    _schema1 = "https";
    _host1 = "www.hwakun.com.cn";
    _port1 = "443";

    _schema2 = "https";
    _host2 = "www.tianqi.com";
    _port2 = "443";

    _schema3 = "http";
    _host3 = "127.0.0.1";
    _port3 = "5000";
}

void mpHttpConnectionManageTests::initTestCase(){}
void mpHttpConnectionManageTests::cleanupTestCase(){}

void exec_connect(boost::asio::io_context& context,
                  const std::string& host,
                  const std::string& port,
                  HttpConnection::ptr_s connection){

    boost::asio::ip::tcp::resolver resolver(context);
    boost::asio::ip::tcp::resolver::query query(host,port);
    boost::asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(query);
    boost::system::error_code err;
    boost::asio::connect(connection->getHttpSocket(), endpoints,err);

    if(err){
        MPLOG_INFO << err.message();
    }
    else{
        connection->changeToConnect();
    }
}

#ifndef MP_JUST_MULTITHREAD

//获取Http连接，优先从POOL缓存池中获取，如没有则自动创建
void mpHttpConnectionManageTests::getHttpConnectionNewCase(){

#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    HttpConnection::ptr_s connection = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    //执行连接
    exec_connect(context,_host,_port,connection);

    QVERIFY2(connection != nullptr,"get http connection new");
    QVERIFY2(connection->isConnected(),"get http connection new is open");

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionNewCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionNewCase");

#endif

}

void mpHttpConnectionManageTests::getHttpConnectionFromPoolCase(){

#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    //创建一个新连接
    HttpConnection::ptr_s connectionNew = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    exec_connect(context,_host,_port,connectionNew);

    if(connectionNew->isConnected()){
        //缓存连接
        manage->recoveryHttpConnection(connectionNew);
        //获取缓存的连接
        auto connectionFromPool = manage->getHttpConnection(_schema,_host,_port,sslSettings);

        QVERIFY2(connectionNew->getId() == connectionFromPool->getId(),"get http connection from pool");
        QVERIFY2(connectionFromPool->isConnected(),"get http connection from pool is open");
    }
    else{
        MPLOG_ERROR << "getHttpConnectionFromPoolCase HTTP CONNECTION IS NOT OPEN";
        //缓存连接
        manage->recoveryHttpConnection(connectionNew);
        //获取缓存的连接
        auto connectionFromPool = manage->getHttpConnection(_schema,_host,_port,sslSettings);

        QVERIFY2(connectionNew->getId() != connectionFromPool->getId(),"get http connection from pool");
    }

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionFromPoolCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionFromPoolCase");

#endif

}


void mpHttpConnectionManageTests::getHttpConnectionFromPoolCase2(){
#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    //创建一个新连接
    HttpConnection::ptr_s connectionNew = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    exec_connect(context,_host,_port,connectionNew);

    if(connectionNew->isConnected()){
        //缓存连接
        manage->recoveryHttpConnection(connectionNew);
        //获取缓存的连接
        auto connectionFromPool = manage->getHttpConnection(_schema,_host,_port,sslSettings);

        QVERIFY2(connectionNew->getId() == connectionFromPool->getId(),"get http connection from pool");
        QVERIFY2(connectionFromPool->isConnected(),"get http connection from pool is open");
    }
    else{
        MPLOG_ERROR << "getHttpConnectionFromPoolCase HTTP CONNECTION IS NOT OPEN";
        //缓存连接
        manage->recoveryHttpConnection(connectionNew);
        //获取缓存的连接
        auto connectionFromPool = manage->getHttpConnection(_schema,_host,_port,sslSettings);

        QVERIFY2(connectionNew->getId() != connectionFromPool->getId(),"get http connection from pool");
    }

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionFromPoolCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionFromPoolCase");

#endif
}

//缓存HTTP连接且缓存具有有效期[受max_cache_seconds约束，默认20秒]
void mpHttpConnectionManageTests::getHttpConnectionFromPoolExpireCase(){
#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    //创建一个新连接
    HttpConnection::ptr_s connectionNew = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    exec_connect(context,_host,_port,connectionNew);

    if(connectionNew->isConnected()){
        //缓存连接
        manage->recoveryHttpConnection(connectionNew);
        //等待20秒
        MP::AppUtils::currentThreadWaiting(22000);
        //获取缓存的连接
        auto connectionFromPool = manage->getHttpConnection(_schema,_host,_port,sslSettings);
        if(!connectionFromPool->isConnected()){
            exec_connect(context,_host,_port,connectionFromPool);
        }

        QVERIFY2(connectionNew->getId() != connectionFromPool->getId(),"get http connection from pool");
    }
    else{
        MPLOG_ERROR << "getHttpConnectionFromPoolExpireCase HTTP CONNECTION IS NOT OPEN";
    }

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionFromPoolExpireCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionFromPoolExpireCase");

#endif
}
//限制Http连接管理器中活动的Http连接数量，超过上限时将无法在获取HTTP连接[受max_count_allocations约束，默认10个]
void mpHttpConnectionManageTests::getHttpConnectionMaxCountCase(){
#ifdef TEST_STRATEGY_COMPLETED


    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    HttpConnection::ptr_s tmps[11]= {};

    for(int i =0;i<11;i++){
        tmps[i] = manage->getHttpConnection(_schema,_host,_port,sslSettings);
        if(i<10){
            exec_connect(context,_host,_port,tmps[i]);
        }
    }

    //一次最多智能创建10个，创建第11个的时候返回nullptr
    QVERIFY2(tmps[9] != nullptr,"getHttpConnectionMaxCountCase");
    QVERIFY2(tmps[10] == nullptr,"getHttpConnectionMaxCountCase");

    //释放其中的一个，就可以再创建一个
    tmps[1].reset();
    auto next = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    QVERIFY2(next != nullptr,"getHttpConnectionMaxCountCase");

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionMaxCountCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionMaxCountCase");

#endif
}
//限制Http连接管理器同一域名缓存的Http连接数量，超过上限时将会自动移除缓存中最早的一个连接[受max_count_preKey约束，默认3个]
void mpHttpConnectionManageTests::getHttpConnectionCacheMaxCountPreKeyCase(){
#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);

    HttpConnection::ptr_s tmps[9]= {};
    //创建10个连接
    for(int i =0;i<9;i++){
        tmps[i] = manage->getHttpConnection(_schema,_host,_port,sslSettings);
        exec_connect(context,_host,_port,tmps[i]);

    }
    //将10个连接逐个缓存值pool中，此时：缓存中应该还有3个，依次数编号为6、7、8的连接
    //ps:pool中使用先进后出的queue容器
    std::string t6_id,t7_id,t8_id;
    for(int i =0;i<9;i++){
        manage->recoveryHttpConnection(tmps[i]);
        if(i==6){
            t6_id = tmps[i]->getId();
        }
        if(i==7){
            t7_id = tmps[i]->getId();
        }
        if(i==8){
            t8_id = tmps[i]->getId();
        }
        tmps[i].reset();
    }

    HttpConnection::ptr_s t6 = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    HttpConnection::ptr_s t7 = manage->getHttpConnection(_schema,_host,_port,sslSettings);
    HttpConnection::ptr_s t8 = manage->getHttpConnection(_schema,_host,_port,sslSettings);

    QVERIFY2(t6->getId() == t6_id,"getHttpConnectionCacheMaxCountPreKeyCase");
    QVERIFY2(t7->getId() == t7_id,"getHttpConnectionCacheMaxCountPreKeyCase");
    QVERIFY2(t8->getId() == t8_id,"getHttpConnectionCacheMaxCountPreKeyCase");

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionCacheMaxCountPreKeyCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionCacheMaxCountPreKeyCase");

#endif
}
//限制Http连接管理器中缓存的Http连接数量，超过上限时将尝试开始清理缓存中超时或已关闭的连接，如仍不足则放弃缓存[受_max_count_inpool约束，默认10个]
void mpHttpConnectionManageTests::getHttpConnectionCacheMaxCountCase(){

#ifdef TEST_STRATEGY_COMPLETED

    SslSettings sslSettings;

    boost::asio::io_context context;
    HttpConnectionManage::ptr_s manage = createHttpConnectionManage(context);
    MP::AppUtils::currentThreadWaiting(62000);

    //先缓存三个(共计三个)
    std::size_t count_prekey = 5;
    HttpConnection::ptr_s tmps[count_prekey]= {};
    for(std::size_t i =0; i < count_prekey; i++){
        tmps[i] = manage->getHttpConnection(_schema,_host,_port,sslSettings);
        exec_connect(context,_host,_port,tmps[i]);
    }
    for(std::size_t i =0; i < count_prekey; i++){
        manage->recoveryHttpConnection(tmps[i]);
    }
    QVERIFY2(manage->getConnectionInPoolCount() == 3,"getHttpConnectionCacheMaxCountCase");


    //再缓存三个(共计六个)
    for(std::size_t i =0; i < count_prekey; i++){
        tmps[i] = manage->getHttpConnection(_schema1,_host1,_port1,sslSettings);
        //exec_connect(context,_host1,_port1,tmps[i]);
    }
    for(std::size_t i =0; i < count_prekey; i++){
        manage->recoveryHttpConnection(tmps[i]);
    }
    QVERIFY2(manage->getConnectionInPoolCount() == 6,"getHttpConnectionCacheMaxCountCase");

    //再缓存三个未连接(共计九个)
    for(std::size_t i =0; i < count_prekey; i++){
        tmps[i] = manage->getHttpConnection(_schema2,_host2,_port2,sslSettings);
        //exec_connect(context,_host2,_port2,tmps[i]);
    }
    for(std::size_t i =0; i < count_prekey; i++){
        manage->recoveryHttpConnection(tmps[i]);
    }
    QVERIFY2(manage->getConnectionInPoolCount() == 9,"getHttpConnectionCacheMaxCountCase");

    //再开始准备测试(共计十个)
    HttpConnection::ptr_s connection10 = manage->getHttpConnection(_schema3,_host3,_port3,sslSettings);
    exec_connect(context,_host3,_port3,connection10);

    HttpConnection::ptr_s connection11 = manage->getHttpConnection(_schema3,_host3,_port3,sslSettings);
    exec_connect(context,_host3,_port3,connection11);

    //(共计十个)
    manage->recoveryHttpConnection(connection10);
    QVERIFY2(manage->getConnectionInPoolCount() == 10,"getHttpConnectionCacheMaxCountCase");

    //(共计五个)将会启动清理,将减少6个未建立连接的连接
    manage->recoveryHttpConnection(connection11);
    QVERIFY2(manage->getConnectionInPoolCount() == 5,"getHttpConnectionCacheMaxCountCase");

    manage->clearAndDeactivate();
    QVERIFY2(manage->getConnectionInUseCount() == 0,"getHttpConnectionCacheMaxCountCase");
    QVERIFY2(manage->getConnectionInPoolCount() == 0,"getHttpConnectionCacheMaxCountCase");

#endif

}

#else
//简单的多线程测试
void mpHttpConnectionManageTests::multithreadingCase(){
#ifdef TEST_STRATEGY_COMPLETED

    std::size_t t_count = 5;
    std::size_t t_repeat_count = 50;
    std::vector<std::thread> threads = {};

    for(std::size_t i = 0;i <t_count;i++){
        std::thread t([&](){
            hcmt.doCase1(t_repeat_count,_schema,_host,_port);
        });
        threads.push_back(std::move(t));
    }

    for(std::size_t i = 0;i <t_count;i++){
        std::thread t([&](){
            hcmt.doCase1(t_repeat_count,_schema1,_host1,_port1);
        });
        t.detach();
    }

    for(std::size_t i = 0;i <t_count;i++){
        std::thread t([&](){
            hcmt.doCase1(t_repeat_count,_schema2,_host2,_port2);
        });
        t.detach();
    }

    for(std::size_t i = 0;i <t_count;i++){
        std::thread t([&](){
            hcmt.doCase1(t_repeat_count,_schema3,_host3,_port3);
        });
        t.detach();
    }

    size_t len = threads.size();
    for (size_t i =0; i < len; i ++)
    {
        std::thread& t = threads[i];
        if(t.joinable()){
            t.join();
        }
    }

    MPLOG_INFO << "multithreadingCase complete";


#endif
}

#endif



